#!/bin/bash
# 安装脚本
# author    : guyadong
# date      : 2019/08/09

sh_folder=$(dirname $(readlink -f $0))

# 脚本初始化
. ./common_init.sh

# 获取发行版本(ubuntu,centos...)
[ -f /etc/os-release ] || exit_on_error "ERROR:NOT FOUND /etc/os-release"
eval dist_id=$(get_value /etc/os-release ID)
. ./native_functions_${dist_id,,}.sh || exit_on_error "不支持当前平台:$dist_id"


function need_install_mysql(){
    [ -n "$(which mysqld 2>/dev/null)" ] && return 1
    [ "$facelog_install" = 'on' ] || [ "$fdevmgr_install" = 'on' ] || return 1
    [ $fdevmgr_db_use_local -eq 0 ] || [ $database_use_local -eq 0 ] ||  return 1    
    return 0
}

function need_install_redis(){
    [ -n "$(which redis-server 2>/dev/null)" ] && return 1    
    [ $redis_use_local -eq 0 ] || return 1    
    return 0
}

function need_install_nginx(){
    [ -n "$(which nginx 2>/dev/null)" ] && return 1
    [ "$fdevmgr_install" != "on" ] && return 1    
    return 0
}

# 根据需要安装所有依赖的第三方软件包
function install_dependencies_if_needed(){
    which wget >/dev/null 2>&1 || install_components wget
    echo  "安装依赖的第三方软件包(install all dependencies)"
    local list="$(need_install_list)"
    [ -z "$list" ] && return 0
    install_components "$list"
    if [[ "$list" == *mysql* ]] 
    then
        # 安装 mysql 后等待 mysql 启动后再返回 
        local port=3306
        [ $fdevmgr_db_use_local -ne 0 ] && port=$database_jdbc_port
        [ $database_use_local -ne 0 ] && port=$fdevmgr_db_port
        echo "WAIT mysql"
        wait_port $port 10 "mysql($port)"
        service_online mysql $port
    fi
    if [[ "$list" == *redis* ]] 
    then
        local port=6379
        # 安装 redis 后等待 redis 启动后再返回 
        echo "WAIT redis"
        wait_port $port 10 "redis($port)"
        service_online redis $port
    fi
    set_status_value 'installed_deps' "${list// /,}"
    echo "==========================="
    return 0
}
# 设置facelog配置文件中的值,如果文件不存在,则先调用init_config_if_need初始化
# $1 key
# $2 value
function facelog_config(){
    if [ ! -f $HOME/$CFG_FOLDER/config.properties ] || [ "$config_initialized" != 'true' ]
    then
        config_initialized=false
        init_config_if_need
    fi
    set_value $HOME/$CFG_FOLDER/config.properties $1 $2
}
# 设置fdevmgr配置文件中的值,如果文件不存在,则先调用init_fdevmgr_if_need初始化
# $1 key
# $2 value
function fdevmgr_config(){
    if [ ! -f $HOME/$CFG_FOLDER/fdevmgr.properties ] || [ "$fdevmgr_initialized" != 'true' ]
    then
        fdevmgr_initialized=false
        init_fdevmgr_if_need
    fi
    set_value $HOME/$CFG_FOLDER/fdevmgr.properties $1 $2
}
# 设置本地 mysql root密码(Debian platforms)
# $1 root password
function update_local_mysql_root_pwd_debian(){
    [ -n "$1" ] || exit_on_error 'root 密码不可为空'
    local debian_cnf_file=/etc/mysql/debian.cnf
    [ -f $debian_cnf_file ] || exit_on_error "ERROR: $debian_cnf_file 不存在，mysql server 安装了么?"
    local debian_cnf="$(eval sudo cat /etc/mysql/debian.cnf)"
    local user=$(get_value_str "$debian_cnf" user) 
    local password=$(get_value_str "$debian_cnf" password)
    [ -n "$user"     ] || exit_on_error "ERROR:没有从 $debian_cnf_file 解析出默认用户名"
    [ -n "$password" ] || exit_on_error "ERROR:没有从 $debian_cnf_file 解析出默认密码"

    # mysql server 版本号    
    get_mysqld_version && echo "mysql version:$mysqld_version" 

    export MYSQL_PWD=$password
    # 设置 root 密码
    # mysql server 版本小于 5.7.6可以用 set password 语法设置密码,参见 https://dev.mysql.com/doc/refman/5.7/en/set-password.html
    # 5.7.6 以后要用 ALTER USER user IDENTIFIED BY 'auth_string' 语法
    local sql_statement=
    if version_ge $mysql_version 5.7.6
    then
        sql_statement="FLUSH PRIVILEGES;ALTER USER 'root'@'localhost' IDENTIFIED BY '$1';"
    else
        sql_statement="FLUSH PRIVILEGES;set password for root@localhost = password('$1');"        
    fi
    echo "$sql_statement"
    mysql -u$user -e "$sql_statement" || exit_on_error
    sql_statement="update user set plugin='mysql_native_password'"
    echo "$sql_statement"
    mysql -u$user -e "$sql_statement" mysql|| exit_on_error
    return 0
}
# 设置本地 mysql root密码(通用平台)
# $1 root password
function update_local_mysql_root_pwd_general(){
    [ -n "$1" ] || exit_on_error 'root 密码不可为空'
    #wait_port  3306 5 'mysql(3306)' 
    sudo systemctl set-environment MYSQLD_OPTS='--skip-grant-tables --skip-networking' || exit_on_error
    sudo systemctl restart mysqld || exit_on_error
    # mysql server 版本号
    get_mysqld_version && echo "mysql version:$mysqld_version" 
    # 获取 mysql.user 表所有字段名
    local user_columns="$(mysql -uroot -e "use mysql;select COLUMN_NAME from information_schema.COLUMNS where table_name='user' and table_schema='mysql'")" 
    [ -n "$user_columns" ] || exit_on_error 'ERROR:获取 mysql.user 表所有字段名'   
    # 保存密码的字段名: authentication_string 或 password
    # mysql 保存密码的字段名有改变，之前是 Password，现在改为 authentication_string
    local pwd_name="$(echo "$user_columns" | grep -iw -o -E '(authentication_string|password)')" 
    [ -n "$pwd_name" ] || exit_on_error "ERROR:在 mysql.user 表中没有找到保存密码的字段,mysql version:$mysql_version"
    # 设置 root 密码
    # mysql server 版本小于 5.7.6可以用 set password 语法设置密码,参见 https://dev.mysql.com/doc/refman/5.7/en/set-password.html
    # 5.7.6 以后要用 ALTER USER user IDENTIFIED BY 'auth_string' 语法，但是这个用法在'-skip-grant-tables'选项启动时不可用.
    # 所以这里用UPDATE 语句直接修改 mysql.user表的密码字段
    if version_ge $mysql_version 5.7.6
    then
        mysql -uroot -e "FLUSH PRIVILEGES;ALTER USER 'root'@'localhost' IDENTIFIED BY '$1'"  || \
        mysql -uroot -e "FLUSH PRIVILEGES;set password for root@localhost=password('$1')"  || \
        mysql -uroot -e "UPDATE user SET $pwd_name=PASSWORD('$1') where USER='root';FLUSH PRIVILEGES" mysql || exit_on_error
    else
        mysql -uroot -e "set password for root@localhost = password('$1')" mysql || exit_on_error
    fi
    sudo systemctl unset-environment MYSQLD_OPTS || exit_on_error
    sudo systemctl restart mysqld || exit_on_error 
    wait_port 3306 4 "mysql(3306)"
    return 0
}
# 设置本地 mysql root密码(RPM platforms)
# $1 root password
function update_local_mysql_root_pwd(){
    which apt 1>/dev/null 2>&1 && update_local_mysql_root_pwd_debian "$1"  && return 0
    #which apt 1>/dev/null 2>&1 && update_local_mysql_root_pwd_linux "$1"  && return 0
    update_local_mysql_root_pwd_general "$1"  && return 0
}
# 从配置文件中读取 root 密码更新本地 mysql root 密码
function reset_local_root_pwd(){
    local root_pwd=root_user
    [ $fdevmgr_db_use_local -ne 0 ] && [ $database_use_local -ne 0 ] && return 0
    [ "$fdevmgr_db_username" = 'root' ] || [ "$database_jdbc_username" = 'root' ] || return 0
    [ $mysql_online -eq 0 ] || exit_on_error 'ERROR:本地 mysql 数据库服务未启动'
    [ "${fdevmgr_install,,}" != 'on' ] || [ "${facelog_install,,}" != 'on' ] || [ $fdevmgr_db_use_local -ne 0 ] || [ $database_use_local -ne 0 ] \
            || [ "$fdevmgr_db_username" = "$database_jdbc_username" ] \
            || exit_on_error "ERROR:当都使用本地数据库时,facelog与fdevmgr配置的数据库访问用户名必须一致 [$database_jdbc_username] VS [$fdevmgr_db_username]"

    [ "${fdevmgr_install,,}" != 'on' ] || [ "${facelog_install,,}" != 'on' ] || [ $fdevmgr_db_use_local -ne 0 ] || [ $database_use_local -ne 0 ] \
            || [ "$fdevmgr_db_password" = "$database_jdbc_password" ] \
            || exit_on_error "ERROR:当都使用本地数据库时,facelog与fdevmgr配置的数据库访问密码必须一致 [$database_jdbc_password] VS [$fdevmgr_db_password]"

    # root 密码    
    [ $fdevmgr_db_use_local -eq 0 ] && [ "$fdevmgr_db_username" = 'root' ] && mysql_root_pwd="$fdevmgr_db_password"
    [ $database_use_local -eq 0 ] && [ "$database_jdbc_username" = 'root' ] && mysql_root_pwd="$database_jdbc_password"
    [ -n "$mysql_root_pwd" ] && root_pwd="$mysql_root_pwd"
    echo "重置root密码为'$root_pwd'"
    update_local_mysql_root_pwd "$root_pwd"
    echo "==========================="
    mysql_root_pwd=$root_pwd
    [ $fdevmgr_db_use_local -eq 0 ] && [ "$fdevmgr_db_username" = 'root' ] && fdevmgr_db_password="$mysql_root_pwd" && update_status_value fdevmgr_db_password
    [ $database_use_local -eq 0 ] && [ "$database_jdbc_username" = 'root' ] && database_jdbc_password="$mysql_root_pwd" && update_status_value database_jdbc_password
    update_status_value mysql_root_pwd
}
function reset_facelog_tables(){
    local facelog_sql="facelog-service/sql/create_table.sql"
    export MYSQL_PWD=$database_jdbc_password
    local conn_param="-h$database_jdbc_host -P$database_jdbc_port -u$database_jdbc_username"
    echo "创建 $database_jdbc_schema 数据库(create database)"
    mysql $conn_param --connect-expired-password -e "drop database if exists $database_jdbc_schema;create database $database_jdbc_schema" || exit_on_error
    echo "执行 $facelog_sql 脚本创建表结构"
    mysql $conn_param --connect-expired-password -D$database_jdbc_schema < $facelog_sql || exit_on_error
}
function reset_fdevmgr_tables(){
    local fdevmgr_sql="fdevmgrWhse/createTable/interest_test.sql"
    export MYSQL_PWD=$fdevmgr_db_password
    conn_param="-h$fdevmgr_db_host -P$fdevmgr_db_port -u$fdevmgr_db_username"
    echo "创建 $fdevmgr_db_schema 数据库(create database)"
    mysql $conn_param -e "drop database if exists $fdevmgr_db_schema;create database $fdevmgr_db_schema" || exit_on_error
    echo "执行 $fdevmgr_sql 脚本创建表结构"
    mysql $conn_param -D$fdevmgr_db_schema < $fdevmgr_sql || exit_on_error

}

# 初始化数据库
function init_database_if_needed(){
    [ "$facelog_install" = 'on' ] || [ "$fdevmgr_install" = 'on' ] || return 0
    if [[ "$database_initialized" != "true" || "$force_initdb" == "true"  \
        || $database_reset_tables -eq 0 || $fdevmgr_db_reset_tables -eq 0 ]]
    then
        echo "数据库初始化"
        reset_local_root_pwd

        [ $database_reset_tables -eq 0 ] && reset_facelog_tables

        [ $fdevmgr_db_reset_tables -eq 0 ] && reset_fdevmgr_tables

        database_initialized='true'
        update_status_value database_initialized
    fi
    if [ "$database_initialized" == "true" ]
    then
        facelog_config 'database.jdbc.host' "$database_jdbc_host"
        facelog_config 'database.jdbc.port' "$database_jdbc_port"
        facelog_config 'database.jdbc.username' "$database_jdbc_username"
        facelog_config 'database.jdbc.password' "$database_jdbc_password"
        facelog_config 'database.jdbc.schema' "$FACELOG_DBNAME"

        fdevmgr_config 'spring.datasource.username' "$fdevmgr_db_username"
        fdevmgr_config 'spring.datasource.password' "$fdevmgr_db_password"
        fdevmgr_config 'spring.datasource.url'      "$(fdevmgr_jdbc_url)"
    fi
    echo "==========================="
}

# 创建自定义端口的  redis 服务配置文件
# $1 redis默认配置文件
# 生成与原文件同目录下名为redis-$port.conf的自定义配置文件
function create_custom_redis_conf(){
    local cnf=$(dirname "$1")/redis-$redis_port.conf
    echo "创建自定义端口($redis_port)的  redis 服务配置文件 $cnf"
    sudo cp -f "$1" "$cnf" || exit_on_error 
    echo pidfile=/var/run/redis/redis-server-$redis_port.pid
    set_config $cnf pidfile /var/run/redis/redis-server-$redis_port.pid 'sudo'
    echo logfile=logfile /var/log/redis/redis-server-$redis_port.log
    set_config $cnf logfile /var/log/redis/redis-server-$redis_port.log 'sudo'
    echo dbfilename=dump-$redis_port.db
    set_config $cnf dbfilename dump-$redis_port.db 'sudo'
    echo port=$redis_port
    set_config $cnf port $redis_port 'sudo'
    echo bind=0.0.0.0
    set_config $cnf bind 0.0.0.0 'sudo'
    if [ -n "$redis_password" ]
    then
        echo requirepass=$redis_password
        set_config $cnf requirepass "$redis_password" 'sudo'
    fi
    sudo chown redis $cnf || exit_on_error

}
# 创建自定义端口的 redis 服务脚本
function create_custom_redis_service(){
    
    if [ -x /etc/init.d/redis-server ]
    then
        echo "创建自定义端口($redis_port)的 redis 服务脚本"
        local svr=/etc/init.d/redis-server-$redis_port
        sudo cp -f /etc/init.d/redis-server $svr || exit_on_error
        echo DAEMON_ARGS=$cnf
        set_value $svr DAEMON_ARGS $cnf 'sudo'
        echo PIDFILE=\$RUNDIR/redis-server-$redis_port.pid
        set_value $svr PIDFILE \$RUNDIR/redis-server-$redis_port.pid 'sudo' 
        sudo sed -i -r "s/#\s*Provides:\s*redis-server/\0\-$redis_port/" $svr || exit_on_error
        return 0
    fi
    if [ -f /usr/lib/systemd/system/redis.service ]
    then
        echo "创建自定义端口($redis_port)的 redis 服务脚本(systemctl)"
        local svr=/etc/systemd/system/redis-server-$redis_port.service
        sudo cp -f /usr/lib/systemd/system/redis.service $svr || exit_on_error
        local ExecStart="/usr/bin/redis-server /etc/redis-$redis_port.conf --supervised systemd"
        echo ExecStart=$ExecStart
        set_value $svr ExecStart "$ExecStart" 'sudo' 
        return 0
    fi
    exit_on_error "ERROR:不知道如何创建 redis 自定义端口服务"
}

# 测试本地redis是否可连接
# 可以连接返回0,否则返回1
function test_redis_conntect(){
    local auth=
    [ -n "$redis_password" ] && auth="-a $redis_password"     
    test  "$(redis-cli $auth -h $redis_host -p $redis_port ping)" = PONG 
}

# 配置本地 redis 自定义端口服务
function setup_local_redis(){
    [ $redis_use_local -ne 0 ] && return 0
    if port_online $redis_port
    then
        # 测试本地redis是否可连接, 如果可连接则不需要修改 redis 配置
        test_redis_conntect && echo "redis 服务($redis_port)配置正常，不需要修改" && return 0        
    fi 
    local cnf=/etc/redis/redis-$redis_port.conf
    # 如果服务在线则停止服务
    if  systemctl status redis-server-$redis_port >/dev/null 2>&1
    then
        sudo service redis-server-$redis_port stop || exit_on_error        
    fi    
    [ -f /etc/redis/redis.conf ]  || [ -f /etc/redis.conf ] || exit_on_error "ERROR:没有找到默认 redis 配置文件(/etc/redis/redis.conf 或 /etc/redis.conf )"
    [ -f /etc/redis/redis.conf ]  && create_custom_redis_conf /etc/redis/redis.conf
    [ -f /etc/redis.conf ]  && create_custom_redis_conf /etc/redis.conf

    create_custom_redis_service

    sudo systemctl daemon-reload
    sudo systemctl enable redis-server-$redis_port
    sudo systemctl restart redis-server-$redis_port
    wait_port $redis_port 4 "redis($redis_port)"
    return 0
}

function init_redis_if_needed(){
    echo "redis连接: $(make_redis_uri)"
    [ $redis_use_local -eq 0 ] && setup_local_redis 
    # 测试本地redis是否可连接, 如果可连接则不需要修改 redis 配置
    ! test_redis_conntect && echo "WARN:redis 服务($(make_redis_uri))当前无法连接"

    # 因为不希望 facelog 启动 redis,所以不设置 redis.exe
    # facelog_config 'redis.exe' "$redis_server_exe"
    facelog_config 'redis.host' $redis_host
    facelog_config 'redis.port' $redis_port
    facelog_config 'redis.password' $redis_password
    facelog_config 'redis.database' $redis_database
   
    fdevmgr_config 'spring.redis.host' $redis_host
    fdevmgr_config 'spring.redis.port' $redis_port
    fdevmgr_config 'spring.redis.password' $redis_password
    fdevmgr_config 'spring.redis.database' $redis_database
    echo "==========================="
}

function init_activemq_if_needed(){
    [ "$mq_type" != "ACTIVEMQ" ] && return 0 
    echo "activemq连接: $(make_activemq_uri)"

    facelog_config 'mq.implType' $mq_type
    facelog_config 'mq.connect.uri' $(make_activemq_uri)
    facelog_config 'mq.connect.pubsub.uri' $(make_activemq_mqtt_uri)
    facelog_config 'mq.connect.pubsub.mqtt' 'true'
    facelog_config 'mq.connect.ws.uri' $(make_activemq_ws_uri)
    facelog_config 'mq.connect.username' $activemq_username
    facelog_config 'mq.connect.password' $activemq_password
   
    fdevmgr_config 'spring.mq.implType' $mq_type
    fdevmgr_config 'spring.mq.uri' $(make_activemq_mqtt_uri)
    fdevmgr_config 'spring.mq.username' $activemq_username
    fdevmgr_config 'spring.mq.password' $activemq_password
    echo "==========================="
}

function init_faceapi_service_if_needed(){
    [ "$facelog_install" != "on" ] && return 0
    [ -z "$faceapi_service_sdkversion" ] && exit_on_error_message '没有定义算法版本号'
    echo "初始化 FaceApi RPC服务参数"
    local prefix="faceapi.service.$faceapi_service_sdkversion"
    [ "$faceapi_service_enable" -eq 0 ] && facelog_config "$prefix.enable" 'true'
    [ "$faceapi_service_enable" -ne 0 ] && facelog_config "$prefix.enable" 'false'
    facelog_config "$prefix.host" $faceapi_service_host
    facelog_config "$prefix.port" $faceapi_service_port   
    echo "==========================="
}

function init_proxy_service_if_needed(){
    echo "初始化 erpc proxy 服务参数"
    [ "$proxy_service_enable" -eq 0 ] && facelog_config "proxy.erpc.enable" 'true'
    [ "$proxy_service_enable" -ne 0 ] && facelog_config "proxy.erpc.enable" 'false'

    [ "$proxy_exe" = "erpc_proxy"      ] && erpc_type=full
    [ "$proxy_exe" = "erpc_proxy_mini" ] && erpc_type=mini

    facelog_config "proxy.erpc.type" $erpc_type
    facelog_config "proxy.erpc.port" $proxy_port
    echo "==========================="
}

# 配置本地 facelog 服务
function setup_facelog_if_needed(){

    [ "$facelog_install" != "on" ] && return 0

    if port_online $facelog_port
    then
        sudo systemctl stop facelog
    fi 
    local svr=/etc/systemd/system/facelog.service
    echo "创建 facelog 服务(端口$facelog_port)脚本:$svr"
    sudo cp -f $sh_folder/facelog.service $svr || exit_on_error
    echo WorkingDirectory="$sh_folder"
    set_value $svr WorkingDirectory "$sh_folder" 'sudo'
    echo ExecStart="$sh_folder/facelog start --hup"
    set_value $svr ExecStart "$sh_folder/facelog start --hup" 'sudo'
    echo ExecStop="$sh_folder/facelog stop"
    set_value $svr ExecStop "$sh_folder/facelog stop" 'sudo'
    local User=$(whoami)
    echo User=$User
    set_value $svr User "$User" 'sudo'
    local Group="$(id -gn)"
    echo Group="$Group"
    set_value $svr Group "$Group" 'sudo'

    sudo systemctl daemon-reload
    sudo systemctl enable facelog
    sudo systemctl restart facelog

    echo "WAIT facelog"
    wait_port $facelog_port 60 "facelog($facelog_port)"

    echo "==========================="
    return 0
}

# 配置本地 erpc proxy 服务
function setup_proxy_if_needed(){

    [ "$proxy_service_enable" -eq 1 ] && return 0
    
    if port_online $proxy_port
    then
        sudo systemctl stop erpc_proxy
    fi 
    local svr=/etc/systemd/system/erpc_proxy.service
    local machine=$(g++ -dumpmachine 2>/dev/null)
    [ -n "$machine" ] || machine=$(gcc -dumpmachine 2>/dev/null)
    [ -n "$machine" ] || exit_on_error "NOT INSTALL g++ or gcc,can't get taget machine"
    local exe="$sh_folder/facelog-service/proxy/$machine/$proxy_exe"
    [ -x "$exe" ] || exit_on_error "NOT FOUND $exe"
    echo "创建 erpc proxy 服务(端口$proxy_port)脚本:$svr"
    sudo cp -f $sh_folder/erpc_proxy.service $svr || exit_on_error
    echo WorkingDirectory="$sh_folder"
    set_value $svr WorkingDirectory "$sh_folder" 'sudo'
    local cmd="$exe --port $facelog_port --proxy_port $proxy_port"
    echo ExecStart="$cmd"
    set_value $svr ExecStart "$cmd" 'sudo'
    local User=$(whoami)
    echo User=$User
    set_value $svr User "$User" 'sudo'
    local Group="$(id -gn)"
    echo Group="$Group"
    set_value $svr Group "$Group" 'sudo'

    sudo systemctl daemon-reload
    sudo systemctl enable erpc_proxy
    sudo systemctl restart erpc_proxy

    echo "WAIT erpc_proxy"
    wait_port $proxy_port 5 "erpc_proxy($proxy_port)"

    echo "==========================="
    return 0
}


function create_fdevmgrweb_nginx_conf(){
    echo "
    client_max_body_size     200m;
    server {
        listen $nginx_port; 
        server_name fdevmgr;
        location / {
            root   $sh_folder/fdevmgrWhse-web/dist;
            index  index.html index.htm;
        }
        location /upload {
            alias  $fdevmgrweb_upload_folder;          #定义上传文件路径
            
            autoindex on;                    # 索引 
            autoindex_exact_size on;         # 显示文件大小 
            autoindex_localtime on;          # 显示文件时间 
            index  index.html index.htm;
        }

        location /fdevmgr {
                proxy_pass http://localhost:$fdevmgr_port;
        }
        location /IFaceLog {
                proxy_pass http://$facelog_host:$DEFAULT_FACELOG_PORT_RESTFUL;
        }
    }
    proxy_connect_timeout 300;
    proxy_send_timeout 300;
    proxy_read_timeout 300;
    proxy_buffer_size 16k;
    proxy_buffers 4 64k;
    proxy_busy_buffers_size 128k;
    proxy_temp_file_write_size 128k;
    "
}

# 设置 nginx fdevmgrweb
function setup_nginx_if_need(){
    [ "$fdevmgr_install" != "on" ] && return 0    
    local def_conf=/etc/nginx/nginx.conf
    if [ ! -f /etc/nginx/nginx.conf.facelog_bak ] 
    then
        # 备份原始的配置文件用uninstall 时恢复
        sudo cp $def_conf /etc/nginx/nginx.conf.facelog_bak || exit_on_error
    fi
    if which getenforce 1>/dev/null 2>&1
    then
        # 有安装 SELINUX 时,user 用 root
        echo "服务帐户(user): root"
        sudo sed -i -E -e 's/^\s*user\s+.*;/user root;/' $def_conf || exit 
    fi

    local include_folder=/etc/nginx/sites-enabled
    local fdevmgr_cnf="$(create_fdevmgrweb_nginx_conf)"
    if [ -d $include_folder ] && grep -q -E "^\s*include\s+$include_folder/\*(\.conf)?" $def_conf
    then
        local cnf=$include_folder/$FDEVMGRWEB_NGINX_CONF
        echo "nginx 初始化 $cnf"
        sudo sh -c "echo '$fdevmgr_cnf' > $cnf" || exit_on_error
        # 删除默认站点
        sudo rm -f /etc/nginx/sites-enabled/default || exit_on_error
        sudo systemctl restart nginx || exit_on_error                                                                                                                                                                                                                                                                                                                                                                                                                                 
        cat $cnf
        echo
        echo "==========================="
        return 0
    fi
    include_folder=/etc/nginx/conf.d
    if [ -d $include_folder ] && grep -q -E "^\s*include\s+$include_folder/\*(\.conf)?" $def_conf
    then
        local cnf=$include_folder/$FDEVMGRWEB_NGINX_CONF
        echo "nginx 初始化 $cnf"
        sudo sh -c "echo '$fdevmgr_cnf' > $cnf" || exit_on_error
        if [ -f $include_folder/default.conf ]
        then
            # 删除默认站点
            if [ ! -f $include_folder/default.conf.facelog_bak ]
            then
                sudo mv $include_folder/default.conf $include_folder/default.conf.facelog_bak || exit_on_error
            else
                sudo rm $include_folder/default.conf.facelog_bak || exit_on_error
            fi
        fi
        sudo systemctl restart nginx || exit_on_error                                                                                                                                                                                                                                                                                                                                                                                                                                 
        cat $cnf
        echo
        echo "==========================="
        return 0
    fi    

    echo "暂时不支持的 nginx 目录结构" 
    echo "运行环境:$(awk -F= '/^PRETTY_NAME/{print $2}' /etc/os-release),nginx版本:$(nginx -v)"
    echo "请手工添加如下配置到 nginx.conf:"
    echo $fdevmgr_cnf
    exit 255
}

# 在 operate.js 中查找:分隔的变量定义
function get_value_from_operate_js(){
    local operate_js="$sh_folder/fdevmgrWhse-web/dist/operate.js"
    [ -f $operate_js ] || exit_on_error "没找到文件:$operate_js"
    grep -E -o "^\s*$1\s*:\s*(['\"]\S+['\"]|[0-9]+)" $operate_js | sed -e 's/\s//g' -e "s/'//g" -e "s/\"//g" -e "s/$1://"
}

# 替换前端代码中的内容
# $1 old string
# $2 new string
function replace_content_of_dist(){
    echo -e "REPLACE \033[33m $1 \033[0m WITH \033[33m$2\033[0m..."

    local dist_folder="$sh_folder/fdevmgrWhse-web/dist"
    [ -d $dist_folder ] || exit_on_error "文件夹不存在:$dist_folder"
    local c=0
    for file in $(get_files "$dist_folder")
    do
        [[ $file =~ \.(jpeg|jpg|gif|png)$ ]] && continue
        if grep -F "$1" $file >/dev/null && echo "modified $file" 
        then
            sed -i "s!${1//./\\.}!$2!g" $file || exit_on_error
            c=$(expr $c + 1)
        fi
    done
    [ $c -eq 0 ] && echo -e "\033[31m WARN:没有文件被更新，代码分析可能出错了.\033[0m"
    [ $c -gt 0 ] && echo -e "\033[32m ${c} file modified\033[0m"
}

# 替换前端代码中引用的 webredis 主机端口号
function replace_webredis_addr(){
  
    # 在 operate.js 查找 webredis 主机端口号定义
    local value=$(get_value_from_operate_js 'sockteIp')
    [ -z "$value" ] && echo '"WARN(警告):没有在 operate.js 找到 webredis 主机端口定义变量 sockteIp "' && return 0
    [ -n "$fdevmgrweb_wrhost" ] || exit_on_error 'fdevmgrweb_wrhost 未定义'
    local new_value=$fdevmgrweb_wrhost:$webredis_port
    echo -e "更新前端脚本中的 webredis 引用地址为 \033[33m$new_value\033[0m..."
    replace_content_of_dist $value $new_value
}
# 替换前端代码中 selfUrlPrefix 引用的主机地址
function replace_selfUrlPrefix(){
  
    # 在 operate.js 查找 selfUrlPrefix 定义
    local value=$(get_value_from_operate_js 'selfUrlPrefix')
    
    [ -z "$value" ] && echo '"WARN(警告)：没有在 operate.js 找到 selfUrlPrefix 定义"'
    [ -n "$fdevmgrweb_selfaddress" ] || exit_on_error 'fdevmgrweb_selfaddress 未定义'
    local new_value=http://$fdevmgrweb_selfaddress:$nginx_port
    echo -e "更新前端脚本中的 \033[33m selfUrlPrefix \033[0m 引用值"
    replace_content_of_dist $value $new_value
}
# 替换前端代码中引用的 MQTT 连接URI
function replace_mqttURI(){
  
    # 在 operate.js 查找 mqttPassword 定义
    local value=$(get_value_from_operate_js 'mqttURI')
    
    [ -z "$value" ] && echo '"WARN(警告):没有在 operate.js 找到 mqttURI 定义"' && return 0
    local new_value=$(make_activemq_ws_uri true)
    echo -e "更新前端脚本中的 \033[33m mqttURI \033[0m 引用值"
    replace_content_of_dist $value ${new_value/$activemq_host/$fdevmgrweb_selfaddress}
}
# 创建 web client
function extract_web_client(){
    local folder="$sh_folder/fdevmgrWhse-web/client"
    "$folder/create_client.sh" --host $fdevmgrweb_selfaddress --port $nginx_port || exit 255
    cp -f "$folder/$WEBCLENT.zip" "$fdevmgrweb_upload_folder" || exit 255
}

# 执行 fdevmgrweb 初始化
function setup_fdevmgrweb_if_need(){
    [ "$fdevmgr_install" != "on" ] && return 0
    echo "fdevmgrweb 初始化"  
    replace_webredis_addr
    replace_selfUrlPrefix
    replace_mqttURI
    extract_web_client
    fdevmgrweb_initialized=true
    set_value ./status 'fdevmgrweb_initialized' 'true'
    echo "==========================="
}

# 配置本地 fdevmgr 服务
function setup_fdevmgr_service_if_need(){

    [ "$fdevmgr_install" != "on" ] && return 0

    if port_online $fdevmgr_port
    then
        sudo systemctl stop fdevmgr
    fi 
    local svr=/etc/systemd/system/fdevmgr.service
    echo "创建 fdevmgr 服务(端口$fdevmgr_port)脚本:$svr"
    sudo cp -f $sh_folder/fdevmgr.service $svr || exit_on_error
    echo WorkingDirectory="$sh_folder"
    set_value $svr WorkingDirectory "$sh_folder" 'sudo'
    echo ExecStart="$sh_folder/fdevmgr start --hup"
    set_value $svr ExecStart "$sh_folder/fdevmgr start --hup" 'sudo'
    echo ExecStop="$sh_folder/fdevmgr stop"
    set_value $svr ExecStop "$sh_folder/fdevmgr stop" 'sudo'
    local User=$(whoami)
    echo User=$User
    set_value $svr User "$User" 'sudo'
    local Group="$(id -gn)"
    echo Group="$Group"
    set_value $svr Group "$Group" 'sudo'

    sudo systemctl daemon-reload
    sudo systemctl enable fdevmgr
    sudo systemctl restart fdevmgr

    echo "等待 fdevmgr($fdevmgr_port)服务启动，有点慢，请耐心"
    wait_port $fdevmgr_port 100 "fdevmgr($fdevmgr_port)"

    echo "==========================="
    return 0
}

function setup_fdevmgr_if_needed(){
    setup_fdevmgrweb_if_need
    setup_nginx_if_need
    setup_fdevmgr_service_if_need
}
# 配置本地 webredis 自定义端口服务
function setup_local_webredis_if_need(){

    [ "$webredis_install" != "on" ] && return 0
    [ $webredis_use_local -ne 0 ] && return 0
    if [ $webredis_npm_init -ne 0 ] || [ ! -d "$sh_folder/webredis/node_modules" ]
    then
        pushd $sh_folder/webredis > /dev/null 2>&1
        echo "执行 webredis npm 初始化"
        npm install || exit_on_error
        popd > /dev/null 2>&1
        webredis_npm_init=0
        update_status_value webredis_npm_init
    fi
    if port_online $webredis_port
    then
        sudo systemctl stop webredis
    fi 
    local svr=/etc/systemd/system/webredis.service
    echo "创建 webredis($webredis_port) 服务脚本:$svr"
    sudo cp -f $sh_folder/webredis/webredis.service $svr || exit_on_error
    local WorkingDirectory="$sh_folder/webredis"
    echo WorkingDirectory=$WorkingDirectory
    set_value $svr WorkingDirectory "$WorkingDirectory" 'sudo'
    local ExecStart="$sh_folder/webredis/webredis start --hup"
    echo ExecStart=$ExecStart
    set_value $svr ExecStart "$ExecStart" 'sudo'
    local User=$(whoami)
    echo User=$User
    set_value $svr User "$User" 'sudo'
    local Group="$(id -gn)"
    echo Group="$Group"
    set_value $svr Group "$Group" 'sudo'

    facelog_config 'webredis.file'  "$sh_folder/webredis/webredis.js"

    sudo systemctl daemon-reload
    sudo systemctl enable webredis
    sudo systemctl restart webredis

    wait_port $webredis_port 20 "webredis($webredis_port)"

    echo "==========================="
    return 0
}
function init_webredis_if_needed(){
    [ "$webredis_install" != "on" ] && return 0

    setup_local_webredis_if_need 
    # 测试 webredis 是否可连接, 如果不可连接则输出警告
    [[ $(curl -s $webredis_host:$webredis_port ) != webredis* ]] && echo "WARN:webredis 服务($webredis_host:$webredis_port)当前无法连接"
    #[[ "$(wget -q -O - http://$webredis_host:$webredis_port)" != webredis* ]] && echo "WARN:webredis 服务($webredis_host:$webredis_port)当前无法连接"
    node_available "$node_exe" || exit_on_error "没有安装 node"
    [ -x "$node_exe" ] && facelog_config 'nodejs.exe' "$node_exe"
    facelog_config 'webredis.port'  "$webredis_port"
    facelog_config 'webredis.host'  "$webredis_host"
}
# 创建 $HOME/.facelog/config.properties文件
# 如果 $HOME/.facelog文件夹存在则改名为.facelog.bak
function init_config_if_need(){

    [ "$config_initialized" = "true" ] && [ "$force_config" != "true"  ] && return
    if [ ! -d "$HOME/$CFG_FOLDER" ] 
    then
        mkdir -p $HOME/$CFG_FOLDER || exit_on_error
    fi
    cp ./config.properties.init $HOME/$CFG_FOLDER/config.properties || exit_on_error

    config_initialized='true'
    set_value $HOME/$CFG_FOLDER/config.properties 'server.port' "$facelog_port"
    set_value $HOME/$CFG_FOLDER/config.properties 'root.password' "$facelog_root_pwd"

    set_value ./status 'config_initialized' 'true'
}
# 执行 fdevmgr 配置文件初始化
function init_fdevmgr_if_need(){
    [ "$fdevmgr_initialized" = 'true' ] && [ "$force_fdevmgr" != 'true' ] && return
    if [ ! -d "$HOME/$CFG_FOLDER" ] 
    then
        mkdir -p $HOME/$CFG_FOLDER || exit_on_error
    fi

    cp -v ./fdevmgr.properties.init $HOME/$CFG_FOLDER/fdevmgr.properties || exit_on_error
    fdevmgr_initialized='true'
    set_value $HOME/$CFG_FOLDER/fdevmgr.properties 'server.port' "$fdevmgr_port"
    set_value $HOME/$CFG_FOLDER/fdevmgr.properties 'fdevmgr.facelog.host' "$facelog_host"
    set_value $HOME/$CFG_FOLDER/fdevmgr.properties 'fdevmgr.facelog.port' "$facelog_port"
    set_value $HOME/$CFG_FOLDER/fdevmgr.properties 'fdevmgr.facelog.rootpwd' "$facelog_root_pwd"
    set_value $HOME/$CFG_FOLDER/fdevmgr.properties 'fdevmgr.properties.downloadpreffix' "http://$fdevmgrweb_selfaddress:$nginx_port"
    set_value $HOME/$CFG_FOLDER/fdevmgr.properties 'fdevmgr.properties.filepath' "$fdevmgrweb_upload_folder"
    set_value ./status 'fdevmgr_initialized' 'true'
}

function setup_firewall(){
    echo "防火墙设置(firewall setup)"
    if [ "$facelog_install"  = 'on'  ]
    then
        firewall_open_port $facelog_port
        firewall_open_port $DEFAULT_FACELOG_PORT_XHR
        firewall_open_port $DEFAULT_FACELOG_PORT_RESTFUL
    else
        firewall_close_port $facelog_port
        firewall_close_port $DEFAULT_FACELOG_PORT_XHR
        firewall_close_port $DEFAULT_FACELOG_PORT_RESTFUL
    fi

    [ $proxy_service_enable -eq 0 ] && firewall_open_port $proxy_port
    [ $proxy_service_enable -eq 1 ] && firewall_close_port $proxy_port

    [ "$webredis_install"  = 'on' ] && firewall_open_port $webredis_port
    [ "$webredis_install" != 'on' ] && firewall_close_port $webredis_port
    [ "$fdevmgr_install"   = 'on' ] && firewall_open_port $fdevmgr_port
    [ "$fdevmgr_install"  != 'on' ] && firewall_close_port $fdevmgr_port
    [ "$fdevmgr_install"   = 'on' ] && firewall_open_port $nginx_port
    [ "$fdevmgr_install"  != 'on' ] && firewall_close_port $nginx_port
    [ $redis_use_local -eq 0      ] && firewall_open_port $redis_port
    [ $redis_use_local -ne 0      ] && firewall_close_port $redis_port
    if [ "$mq_type" = "ACTIVEMQ" ]
    then
        firewall_open_port $activemq_port
        firewall_open_port $activemq_mqtt_port
        firewall_open_port $activemq_ws_port
    fi
    firewall_reload
    echo "==========================="
    return 0
}

# 返回可以访问本机 facelog服务的 swagger url(逗号分隔)
function local_facelog_swagger_urls(){
    # 如果安装了 fdevmgr 服务直接使用定义的fdevmgrweb_selfaddress变量值
    [ "$fdevmgr_install" = 'on' ] && echo "http://$fdevmgrweb_selfaddress:$DEFAULT_FACELOG_PORT_RESTFUL/swagger-ui.html" && return 0
    local ips=($(nic_info))
    local port=
    echo "${ips[@]}" | sed -E -e "s!(.*)\[.*\]!http://\\1:$DEFAULT_FACELOG_PORT_RESTFUL/swagger-ui.html!g" -e 's!\\s+!,!g'
}
install_base_utils

install_dependencies_if_needed
init_database_if_needed 
init_redis_if_needed
init_activemq_if_needed
init_webredis_if_needed
init_faceapi_service_if_needed
init_proxy_service_if_needed
setup_facelog_if_needed
setup_proxy_if_needed
setup_fdevmgr_if_needed
setup_firewall

echo ""
echo -e "\033[32m 安装结束\033[0m"
[ "$facelog_install" = 'on' ] && \
    echo -e "\033[32m 现在可以用浏览器(chrome,firefox)访问facelog 接口文档: $(local_facelog_swagger_urls)\033[0m"
[ "$fdevmgr_install" = 'on' ] && \
    echo -e "\033[32m 现在可以用浏览器(chrome,firefox)访问 http://$fdevmgrweb_selfaddress:$nginx_port 登录管理后台\033[0m" && \
    echo -e "\033[32m windows(x64)平台也可以使用专用客户端程序，下载地址 http://$fdevmgrweb_selfaddress:$nginx_port/upload/fdevmgr-win32-x64.zip  \033[0m"
echo -e "\033[32m enjoy it\033[0m"


